#include <stdio.h>
#include <stdlib.h>

#include "World.h"

int WorldHeight = 0;
int WorldWidth = 0;

int** mWorld;

void World_Init(int WidthHeight)
{
    int X,Y;
    int X2, Y2;
    int i, a;
    int Height = WidthHeight;
    int Width = WidthHeight;

    /* Karte erstellen */
    mWorld = malloc(Width * sizeof(int*));
    for(i = 0; i < Width; i++)
        mWorld[i] = malloc( Height * sizeof(int));

    /* Ganze map leeren */
    for(X = 0; X < Width; X++)
        for(Y = 0; Y < Height; Y++)
            mWorld[X][Y] = 1;

    /* Breite speichern */
    WorldHeight = Height;
    WorldWidth = Width;

    /* Wälder */
    for(i = 0; i < (WorldHeight*WorldWidth)/144; i++)
    {
        X = RandomRange( 0, WorldWidth);
        Y = RandomRange( 0, WorldHeight);

        //mWorld[X][Y] = 2;
        switch(RandomRange(0,20))
        {
            default:
                for(a = 0; a < 24; a++)
                {
                    X2 = abs(X+RandomRange(-5,5));
                    Y2 = abs(Y+RandomRange( -5, 5));
                    if(X2>=WorldWidth-1)
                        X2 = WorldWidth-1;
                    if(Y2>=WorldHeight-1)
                        Y2 = WorldHeight-1;
                    mWorld[X2][Y2] = 20+RandomRange(0,18);
                }
            break;
            case 1:
                for(a = 0; a < 10; a++)
                {
                    X2 = X+RandomRange(-3,3);
                    Y2 = Y+RandomRange( -3, 3);
                    if(X2>=WorldWidth-1)
                        X2 = WorldWidth-1;
                    if(Y2>=WorldHeight-1)
                        Y2 = WorldHeight-1;
                    mWorld[abs(X2)][abs(Y2)] = TILE_EMPTY;
                }
            break;
            case 2:
                for(a = 0; a < 5; a++)
                {
                    X2 = X+RandomRange(-2,2);
                    Y2 = Y+RandomRange( -2, 2);
                    if(X2>=WorldWidth-1)
                        X2 = WorldWidth-1;
                    if(Y2>=WorldHeight-1)
                        Y2 = WorldHeight-1;
                    mWorld[abs(X2)][abs(Y2)] = 100;
                }
            break;
        }
    }

    /* Die Grenzen */
    for(i = 0; i < WorldWidth; i++)
    {
        for(a = 0; a < 2; a++)
        {
            X2 = i+RandomRange(-2, 2);
            Y2 = 0+RandomRange( -2, 2);
            if(X2>=WorldWidth-1)
                X2 = WorldWidth-1;
            if(Y2>=WorldHeight-1)
                Y2 = WorldHeight-1;
            mWorld[abs(X2)][abs(Y2)] = TILE_EMPTY;
        }
    }
    for(i = 0; i < WorldWidth; i++)
    {
        for(a = 0; a < 2; a++)
        {
            X2 = 0+RandomRange(-2, 2);
            Y2 = i+RandomRange( -2, 2);
            if(X2>=WorldWidth-1)
                X2 = WorldWidth-1;
            if(Y2>=WorldHeight-1)
                Y2 = WorldHeight-1;
            mWorld[abs(X2)][abs(Y2)] = TILE_EMPTY;
        }
    }
    for(i = 0; i < WorldWidth; i++)
    {
        for(a = 0; a < 2; a++)
        {
            X2 = WorldWidth+RandomRange(-2, 2);
            Y2 = i+RandomRange( -2, 2);
            if(X2>=WorldWidth-1)
                X2 = WorldWidth-1;
            if(Y2>=WorldHeight-1)
                Y2 = WorldHeight-1;
            mWorld[abs(X2)][abs(Y2)] = TILE_EMPTY;
        }
    }
    for(i = 0; i < WorldWidth; i++)
    {
        for(a = 0; a < 2; a++)
        {
            X2 = i+RandomRange(-2, 2);
            Y2 = WorldHeight+RandomRange( -2, 2);
            if(X2>=WorldWidth-1)
                X2 = WorldWidth-1;
            if(Y2>=WorldHeight-1)
                Y2 = WorldHeight-1;
            mWorld[abs(X2)][abs(Y2)] = TILE_EMPTY;
        }
    }
    /* Camera setzen */
    Graphic_SetCamera(WorldWidth*60+64,WorldHeight*30+64);
    Graphic_CentralCamera( WorldWidth, WorldHeight);

    World_SetTile(30,38, 60);
    World_SetTile(30,39, 61);
    World_SetTile(30,40, 62);
    World_SetTile(30,41, 63);
    World_SetTile(30,42, 80);

    logDebug("World size: %dkB", (sizeof(mWorld)*Width)+(sizeof(mWorld[0])*Height)/1024);
}

/* Abfragen einer Tile */
int World_Tile(int X, int Y)
{
    if(X < 0)
        return 0;
    if(Y < 0)
        return 0;
    if( X >= WorldWidth)
        return 0;
    if( Y >= WorldHeight)
        return 0;
    return mWorld[X][Y];
}

/* Setzen einer Tile */
void World_SetTile(int X, int Y, int Data)
{
    if(X < 0)
        return;
    if(Y < 0)
        return;
    if( X >= WorldWidth)
        return;
    if( Y >= WorldHeight)
        return;

    mWorld[X][Y] = Data;
}

void World_SetUp(int mX, int mY, int i2)
{
    int Data = 0;
    switch(i2)
    {
        case TILE_ROAD:     Data =  TILE_ROAD_S; break;
        case TILE_ROAD_W:   Data = TILE_ROAD_SW; break;
        case TILE_ROAD_E:   Data = TILE_ROAD_SE; break;
        case TILE_ROAD_N:   Data = TILE_ROAD_NS; break;
        case TILE_ROAD_EW:  Data = TILE_ROAD_SEW; break;
        case TILE_ROAD_NE:  Data = TILE_ROAD_NSE; break;
        case TILE_ROAD_NW:  Data = TILE_ROAD_NSW; break;
        case TILE_ROAD_NEW: Data = TILE_ROAD_NSEW; break;
        default: return; break;
    }
    World_SetTile(mX, mY-1, Data);
    return;
}

void World_SetLeft(int mX, int mY, int i4)
{
    int Data = 0;
    switch(i4)
    {
        case TILE_ROAD: Data = TILE_ROAD_E; break;
        case TILE_ROAD_S: Data = TILE_ROAD_SE; break;
        case TILE_ROAD_N: Data = TILE_ROAD_NE; break;
        case TILE_ROAD_W: Data = TILE_ROAD_EW; break;
        case TILE_ROAD_NS: Data = TILE_ROAD_NSE; break;
        case TILE_ROAD_NW: Data = TILE_ROAD_NEW; break;
        case TILE_ROAD_SW: Data = TILE_ROAD_SEW; break;
        case TILE_ROAD_NSW: Data = TILE_ROAD_NSEW; break;
        default: return; break;
    }
    World_SetTile(mX-1, mY, Data);
    return;
}

void World_SetRight(int mX, int mY, int i6)
{
    int Data = 0;
    switch(i6)
    {
        case TILE_ROAD: Data = TILE_ROAD_W; break;
        case TILE_ROAD_E: Data = TILE_ROAD_EW; break;
        case TILE_ROAD_N: Data = TILE_ROAD_NW; break;
        case TILE_ROAD_S: Data = TILE_ROAD_SW; break;
        case TILE_ROAD_NE: Data = TILE_ROAD_NEW; break;
        case TILE_ROAD_SE: Data = TILE_ROAD_SEW; break;
        case TILE_ROAD_NS: Data = TILE_ROAD_NSW; break;
        case TILE_ROAD_NSE: Data = TILE_ROAD_NSEW; break;
        default: return; break;
    }
    World_SetTile(mX+1, mY, Data);
    return;
}
void World_SetDown(int mX, int mY, int i8)
{
    int Data = 0;
    switch(i8)
    {
        case TILE_ROAD: Data = TILE_ROAD_N; break;
        case TILE_ROAD_E: Data = TILE_ROAD_NE; break;
        case TILE_ROAD_S: Data = TILE_ROAD_NS; break;
        case TILE_ROAD_W: Data = TILE_ROAD_NW; break;
        case TILE_ROAD_SE: Data = TILE_ROAD_NSE; break;
        case TILE_ROAD_SW: Data = TILE_ROAD_NSW; break;
        case TILE_ROAD_EW: Data =  TILE_ROAD_NEW; break;
        case TILE_ROAD_SEW: Data = TILE_ROAD_NSEW; break;
        default: return; break;
    }
    World_SetTile(mX, mY+1, Data);
    return;
}

void World_Road(int X, int Y)
{
    float mX, mY;

    /* Berechnung der Pos. auf der Karte 2D->Iso */
    mX = ((X-(WorldWidth*30)+(Y*30/15))) / 60;
    mY = ( ( (Y*2) - (X-(WorldWidth*30) ) ))/60;

    /* Nun umgewandelt die hauptfunktion ausführen */
    World_RoadIso((int)mX, (int)mY);
}

/* Ob es eine Straße ist (Negativ!) */
int World_GetRoadID(int ID) {
    if(ID < 4 || ID >= 20)
        return 1;
    return 0;
}

/* Ob der Platz bebaubar ist  */
int World_TileFree(int ID) {
    if(ID != 1 && World_GetRoadID(ID))
        return 1;
    return 0;
}

void World_SetBuilding(int mX, int mY, int ID)
{
    int i2;
    int i4,i6;
    int i8;

    /* Platz Tile abfragen */
    i2 = World_Tile( mX, mY);
    if(World_TileFree(i2))
        return;

    /* Setzten */
    World_SetTile( mX, mY, ID);

    /* Nach straßen suchen */
    i2 = World_Tile(mX  , mY-1);
    i4 = World_Tile(mX-1, mY);
    i6 = World_Tile(mX+1, mY);
    i8 = World_Tile(mX  , mY+1);

    /* Sich verbinnden lassen */
    if(!World_GetRoadID(i2))
        World_RoadIso( mX, mY-1);
    if(!World_GetRoadID(i4))
        World_RoadIso( mX-1, mY);
    if(!World_GetRoadID(i6))
        World_RoadIso( mX+1, mY);
    if(!World_GetRoadID(i8))
        World_RoadIso( mX, mY+1);

}

void World_RoadIso(int mX, int mY)
{
    int i2;
    int i4,i6;
    int i8;

    /* Tile abfragen */
    i2 = World_Tile(mX  , mY);
    if(World_TileFree(i2))
        return;

    /* Sich verbinnden lassen */
    i2 = World_Tile(mX  , mY-1);
    i4 = World_Tile(mX-1, mY);
    i6 = World_Tile(mX+1, mY);
    i8 = World_Tile(mX  , mY+1);

    /* Ob es wege sind */
    if(World_GetRoadID(i2))
        if(i2 < TILE_HOUSE_S || i2 >= TILE_HOUSE_S_Max) i2 = 0;
    if(World_GetRoadID(i4))
        if(i4 < TILE_HOUSE_E || i4 >= TILE_HOUSE_E_Max) i4 = 0;
    if(World_GetRoadID(i6)) i6 = 0;
    if(World_GetRoadID(i8)) i8 = 0;

    /* nsew */
    if(i2 && i4 && i6 && i8)
    {
        World_SetUp(mX, mY, i2);
        World_SetRight(mX, mY, i6);
        World_SetLeft(mX, mY, i4);
        World_SetDown(mX, mY, i8);
        World_SetTile(mX,mY, TILE_ROAD_NSEW);
        return;
    }
    /* new */
    if(i2 && i4 && i6)
    {
        World_SetUp(mX, mY, i2);
        World_SetRight(mX, mY, i6);
        World_SetLeft(mX, mY, i4);
        World_SetTile(mX,mY,TILE_ROAD_NEW);
        return;
    }
    /* sew */
    if(i8 && i4 && i6)
    {
        World_SetRight(mX, mY, i6);
        World_SetLeft(mX, mY, i4);
        World_SetDown(mX, mY, i8);
        World_SetTile(mX,mY,TILE_ROAD_SEW);
        return;
    }
    /* nsw */
    if(i2 && i4 && i8)
    {
        World_SetUp(mX, mY, i2);
        World_SetLeft(mX, mY, i4);
        World_SetDown(mX, mY, i8);
        World_SetTile(mX,mY,TILE_ROAD_NSW);
        return;
    }
    /* nse */
    if(i2 && i6 && i8)
    {
        World_SetUp(mX, mY, i2);
        World_SetRight(mX, mY, i6);
        World_SetDown(mX, mY, i8);
        World_SetTile(mX,mY,TILE_ROAD_NSE);
        return;
    }
    /* se */
    if(i6 && i8)
    {
        World_SetRight(mX, mY, i6);
        World_SetDown(mX, mY, i8);
        World_SetTile(mX,mY,TILE_ROAD_SE);
        return;
    }
    /* sw */
    if(i4 && i8)
    {
        World_SetLeft(mX, mY, i4);
        World_SetDown(mX, mY, i8);
        World_SetTile(mX,mY,TILE_ROAD_SW);
        return;
    }
    /* nw */
    if(i2 && i4)
    {
        World_SetUp(mX, mY, i2);
        World_SetLeft(mX, mY, i4);
        World_SetTile(mX,mY,TILE_ROAD_NW);
        return;
    }
    /* ne */
    if(i2 && i6)
    {
        World_SetUp(mX, mY, i2);
        World_SetRight(mX, mY, i6);
        World_SetTile(mX,mY,TILE_ROAD_NE);
        return;
    }
    /* ns */
    if(i2 && i8)
    {
        World_SetUp(mX, mY, i2);
        World_SetDown(mX, mY, i8);
        World_SetTile(mX,mY,TILE_ROAD_NS);
        return;
    }
    /* we */
    if(i4 && i6)
    {
        World_SetLeft(mX, mY, i4);
        World_SetRight(mX, mY, i6);
        World_SetTile(mX,mY,TILE_ROAD_EW);
        return;
    }
    /* n */
    if(i2)
    {
        World_SetUp(mX, mY, i2);
        World_SetTile(mX,mY,TILE_ROAD_N);
        return;
    }
    /* S */
    if(i8)
    {
        World_SetDown(mX, mY, i8);
        World_SetTile(mX,mY,TILE_ROAD_S);
        return;
    }
    /* W */
    if(i4)
    {
        World_SetLeft(mX, mY, i4);
        World_SetTile(mX,mY,TILE_ROAD_W);
        return;
    }
    /* E */
    if(i6)
    {
        World_SetRight(mX, mY, i6);
        World_SetTile(mX,mY,TILE_ROAD_E);
        return;
    }
    World_SetTile(mX,mY,TILE_ROAD);
    return;
}

void World_Process()
{
    int X = 0, Y = 0;

    /* Jede Tile einzeln Zeichnen */
    for(X = 0; X < WorldWidth; X++)
        for(Y = 0; Y < WorldHeight; Y++)
        {
            Graphic_Tile( X, Y, mWorld[X][Y]);
        }
}

float Random()
{
    return rand() / (float)RAND_MAX;
}

int RandomRange( int low, int high )
{
    int range = high - low;
    return (int) (Random() * range) + low;
}
